/**
 * 交叉编译template中的javascript和html，并渲染dom
 * @param {Object} model 数据
 * @param {Boolean} openLog 是否在控制台打印日志，默认为false
 * @returns HTMLElement
 */
 HTMLElement.prototype._stirring = function (model, openLog) {
     /*思路：
        1：获取到template的innerHTML，切割成一行一行
        2：对每一行进行分析，如果该行以大括号开始，或者以大括号或分号结束，则认定为javascript代码，否则认定我html代码
        3：将javascript代码和html代码构建成一个拼凑html字符串的动态函数__fun__
        4：在__fun__上调用call函数，传入model，使模板代码中的this指向model
        5: __fun__函数调用call之后，将返回一个编译好的html字符串，将该字符串插入到tempate原来的位置，交给浏览器完成渲染
      */
    const REG_SPLITE = /(?:\n\r?)+/;            //捕获空行
    const REG_JS = /(^\s*({|}))|(({|}|;)\s*$)/; //捕获javascript行

    let text = this.innerHTML.trim();
    if (!text) {
        return;
    }

    let textArray = text.split(REG_SPLITE);
    let compiledArray = ["let _html='';"];
    for (let i = 0; i < textArray.length; i++) {
        let row = textArray[i];
        if (REG_JS.test(row)) {
            row = row.replace(/&lt;/g, "<");    //将编码后的小于号解码
            row = row.replace(/&gt;/g, ">");    //将编码后的大于号解码
            row = row.trim();                   //去除两端的空格
            compiledArray.push(row);
        } else {
            row = row.replace(/`/g, "\\`");     //将内容中的反引号转义，使其能够插入到模板字符串中
            compiledArray.push("_html+=`" + row + "\\n`;");
        }
    }
    compiledArray.push("return _html;");

    //编译
    let compiledCode = compiledArray.join("\n");
    let __fun__ = new Function(compiledCode);
    if (openLog) {
        console.log("-----编译结果-----");
        console.log(__fun__);
    }

    //渲染
    let html = __fun__.call(model);
    this.insertAdjacentHTML("beforebegin", html);
    let element = this.previousElementSibling;
    let parent = this.parentElement||this.parentNode;
    parent.removeChild(this);
    if (openLog) {
        console.log("-----渲染结果-----\n" + element.outerHTML);
    }

    return element;
}